package com.ruubypay.biz.mvc.api.service.impl;

import com.ruubypay.biz.activiti.CommonProcessService;
import com.ruubypay.biz.mvc.api.model.request.*;
import com.ruubypay.biz.mvc.api.model.response.OutGoingDetail;
import com.ruubypay.biz.mvc.api.model.response.ProcessDetails;
import com.ruubypay.biz.mvc.api.model.response.TaskEntity;
import com.ruubypay.biz.mvc.api.service.ProcessTaskService;
import com.ruubypay.biz.mvc.workflow.model.response.AuditProcessResponse;
import com.ruubypay.web.common.page.DataGrid;
import com.ruubypay.web.common.utils.StringUtils;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 和工作流任务相关的接口实现类
 * @author chenhaiyang
 */
@Service("processTaskService")
public class ProcessTaskServiceImpl extends CommonProcessService implements ProcessTaskService{

    @Resource
    private ProcessEngine processEngine;

    /**
     * 获取某一个用户当前活跃的请求类
     * @param queryTaskList 查询请求vo类
     * @return 返回该用户的任务
     */
    @Override
    public DataGrid getUserTaskActive(QueryTask queryTaskList) {

        //已经签收的任务
        List<TaskEntity> assignedTask = getAssignedTask(processEngine,queryTaskList);
        //未签收的任务
        List<TaskEntity> unAssignedTask = getUnAssignedTask(processEngine,queryTaskList);

        //分页信息
        Integer pageNumber = Optional.ofNullable(queryTaskList.getPageNumber()).orElse(1);
        Integer pageSize = Optional.ofNullable(queryTaskList.getPageSize()).orElse(10);

        List<TaskEntity> taskEntities =  Stream.of(assignedTask,unAssignedTask)
                .flatMap(List::stream)
                .skip((pageNumber-1)*pageSize)
                .limit(pageSize)
                .sorted((t1,t2)->((int)(t2.getCreateTime().getTime()-t1.getCreateTime().getTime())))
                .collect(Collectors.toList());

       return new DataGrid(assignedTask.size()+unAssignedTask.size(),taskEntities);
    }

    /**
     * 根据用户信息查询已完成的任务
     * @param queryTaskList 查询实体
     * @return 返回已经完成的任务的列表
     */
    @Override
    public DataGrid getUserTaskFinisned(QueryTask queryTaskList) {

        HistoricTaskInstanceQuery histTaskQuery = processEngine.getHistoryService()
                .createHistoricTaskInstanceQuery()
                .taskAssignee(queryTaskList.getUserName())
                .finished()
                .includeProcessVariables()
                .orderByHistoricTaskInstanceEndTime()
                .desc();

        // 设置查询条件
        if (queryTaskList.getBeginDate() != null){
            histTaskQuery.taskCompletedAfter(queryTaskList.getBeginDate());
        }
        if (queryTaskList.getEndDate() != null){
            histTaskQuery.taskCompletedBefore(queryTaskList.getEndDate());
        }
        //分页信息
        Integer pageNumber = Optional.ofNullable(queryTaskList.getPageNumber()).orElse(1);
        Integer pageSize = Optional.ofNullable(queryTaskList.getPageSize()).orElse(10);
        List<HistoricTaskInstance> historyTasks = histTaskQuery.listPage((pageNumber-1)*pageSize,pageSize);

       List<TaskEntity> tasks = Optional.ofNullable(historyTasks)
               .map(List::stream)
               .orElseGet(Stream::empty)
               .map(history->buildTaskEntityByHistory(processEngine,history))
               .collect(Collectors.toList());

       return new DataGrid(histTaskQuery.count(),tasks);
    }

    /**
     * 发起流程
     * @param startProcess 发起流程请求VO类
     * @throws Exception 流程启动失败抛出异常
     */
    @Override
    public void startProcessBykey(StartProcess startProcess) throws Exception{
        processEngine.getIdentityService().setAuthenticatedUserId(startProcess.getStartUserName());


        if(startProcess.getProcessVariables()==null){
            startProcess.setProcessVariables(new HashMap<>(16));
        }
        //添加和当前发起的具体流程的标题，和业务相关
        if(StringUtils.isNotBlank(startProcess.getTitle())){
            startProcess.getProcessVariables().put("title",startProcess.getTitle());
        }

        processEngine.getRuntimeService().startProcessInstanceByKey(startProcess.getKey(),
                startProcess.getBusinessKey(), startProcess.getProcessVariables());
    }

    /**
     * 签收任务
     * @param claimTask 签收任务实体
     * @throws Exception 签收失败异常
     */
    @Override
    public void claimTask(ClaimTask claimTask) throws Exception {
        processEngine.getTaskService().claim(claimTask.getTaskId(),claimTask.getUserName());
    }

    /**
     * 提交任务
     * @param submitTask 提交任务请求类VO
     * @throws Exception 流程提交失败发出异常
     */
    @Override
    public void sumbitTask(SubmitTask submitTask) throws Exception {

        if(StringUtils.isNotBlank(submitTask.getComment())){
            processEngine.getTaskService().addComment(submitTask.getTaskId(),
                    submitTask.getProcessInstanceId(),submitTask.getComment());
        }
        if(submitTask.getProcessVariables()==null){
            submitTask.setProcessVariables(new HashMap<>(16));
        }
        processEngine.getTaskService().complete(submitTask.getTaskId(),submitTask.getProcessVariables());
    }

    /**
     * 查询流程跟踪结果
     * @param queryProcessInfo 查询流程跟踪信息VO类
     * @return 返回流程跟踪的相关信息
     * @throws IOException 异常
     */
    @Override
    public ProcessDetails queryProcessInfo(QueryProcessInfo queryProcessInfo) throws IOException {

        List<AuditProcessResponse> auditProcessDetails= getHistoicFlowList(processEngine,queryProcessInfo.getProcessInstanceId());
        String png =getNowTaskPngByProcessInstanceId(processEngine,queryProcessInfo.getProcessInstanceId());

        return new ProcessDetails(auditProcessDetails,png);
    }

    /**
     * 返回 当前任务的连线
     * @param outgoingQuery 连线查询对象
     * @return List<OutGoingDetail> 将办任务的所有连线
     */
    @Override
    public List<OutGoingDetail> getOutComingLines(QueryOutGoingLines outgoingQuery) {
        //1:使用任务ID，查询任务对象
        Task task = processEngine.getTaskService().createTaskQuery()
                .taskId(outgoingQuery.getTaskId())
                .active()
                .singleResult();
        //3：查询ProcessDefinitionEntiy对象
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)
                processEngine.getRepositoryService()
                        .getProcessDefinition(task.getProcessDefinitionId());
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        ProcessInstance pi = processEngine.getRuntimeService().createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .singleResult();
        //获取当前的活动
        ExecutionEntity execution = (ExecutionEntity) processEngine.getRuntimeService()
                .createProcessInstanceQuery()
                .processInstanceId(pi.getProcessInstanceId())
                .singleResult();

        //获取下一个节点信息
        ActivityImpl activityImpl = processDefinitionEntity.findActivity(execution.getActivityId());
        List<PvmTransition> outgoingLins = getOutGoingLines(activityImpl);

        return Optional.ofNullable(outgoingLins)
                .map(List::stream)
                .orElseGet(Stream::empty)
                .map(this::buildOutGoingDetail)
                .collect(Collectors.toList());
    }

    /**
     * 任务指派（当前任务办理者不想办理，将任务指派给他人）
     * @param assignedTask 指派vo类
     */
    @Override
    public void assigneeTask(AssignedTask assignedTask) {

        Task task =processEngine.getTaskService().createTaskQuery()
                .taskId(assignedTask.getTaskId())
                .singleResult();

        //如果任务的认领者是空，整个时候不能指派，先签收任务再指派
        if(StringUtils.isBlank(task.getAssignee())){
            throw new RuntimeException("未被签收的任务不能指派！");
        }

        processEngine.getTaskService()
                .setAssignee(assignedTask.getTaskId(),null);

        String[] users = assignedTask.getUsers().split(",");

        Arrays.stream(users)
                .forEach(user->{
                    processEngine.getTaskService().deleteCandidateUser(assignedTask.getTaskId(),user);
                    processEngine.getTaskService().addCandidateUser(assignedTask.getTaskId(),user);
                });
    }

}
